/* Copyright(C) 2006-2008 Dave Sexton  *
 * http://www.codeplex.com/aip         *
 * http://www.codeplex.com/aip/license *
 ***************************************/
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Collections.ObjectModel;

namespace DaveSexton.Web.Controls
{
	/// <summary>
	/// An abstract base class that generates an image for a given <see cref="AutoInputProtectionTextProvider"/> implementation and 
	/// a collection of <see cref="AutoInputProtectionFilterProvider"/> implementations.
	/// </summary>
	/// <remarks>
	/// <para>
	/// An implementation of <see cref="AutoInputProtectionImageProvider"/> is responsible for creating an instance of a type that
	/// implements AutoInputProtectionImage.
	/// </para>
	/// <para>
	/// One built-in implementation is an abstract base class named, <see cref="BackgroundAutoInputProtectionImage"/>, which provides
	/// an implementation for <see cref="CreateSurfaceImage"/> that renders a background image that is specified by a derived type.
	/// </para>
	/// <para>
	/// Another built-in implementation is a class named, <see cref="PartitionedAutoInputProtectionImage"/>, which 
	/// renders the individual characters of the text provided by the <see cref="AutoInputProtectionTextProvider"/> into vertical 
	/// partitions, with options for randomizing character rotation and specifying fonts and the image's margins.
	/// <see cref="PartitionedAutoInputProtectionImage"/> derives from <see cref="BackgroundAutoInputProtectionImage"/>.
	/// </para>
	/// <para>
	/// One built-in implementation named, <see cref="LineNoiseAutoInputProtectionImage"/> derives from 
	/// <see cref="PartitionedAutoInputProtectionImage"/>.  It creates a surface bitmap that consists of a white background with
	/// random lines drawn in a variety of sample colors, which are specified by the <see cref="LineNoiseAutoInputProtectionImageProvider"/>
	/// that creates it.
	/// </para>
	/// </remarks>
	/// <include file='examples.xml' path='//example[@id="Background"][@type="images"]'/>
	/// <include file='examples.xml' path='//example[@id="Background"][@type="config"]'/>
	/// <seealso cref="AutoInputProtectionImageProvider"/>
	public abstract class BackgroundAutoInputProtectionImage : AutoInputProtectionImage
	{
		#region Public Properties
		/// <summary>
		/// Gets the <see cref="Image"/> that will be rendered in the background of the <see cref="AutoInputProtectionImage.CompositeImage"/>.
		/// </summary>
		/// <remarks>
		/// The base implementation simply returns the value of this property from the <see cref="CreateSurfaceImage"/>
		/// method; however, derived types can override that method to use the image in a different way.
		/// </remarks>
		public Image Background
		{
			get
			{
				return background;
			}
		}
		#endregion

		#region Private / Protected
		private readonly Image background;
		#endregion

		#region Constructors
		/// <summary>
		/// Constructs a new instance of the <see cref="BackgroundAutoInputProtectionImage" /> class for derived classes.
		/// </summary>
		/// <exception cref="ArgumentNullException">The specified <paramref name="textProvider"/> is <see langword="null"/>.</exception>
		/// <exception cref="ArgumentOutOfRangeException">The specified <paramref name="size"/> is less than the value of 
		/// <see cref="AutoInputProtectionImage.MinimumSize"/>.</exception>
		/// <param name="size">The dimensions of the <see cref="AutoInputProtectionImage.CompositeImage"/></param>
		/// <param name="textProvider">The <see cref="AutoInputProtectionTextProvider"/> implementation that generates the 
		/// <see cref="AutoInputProtectionImage.Text"/> for the <see cref="AutoInputProtectionImage.CompositeImage"/>.</param>
		protected BackgroundAutoInputProtectionImage(Size size, AutoInputProtectionTextProvider textProvider)
			: base(size, textProvider)
		{
		}

		/// <summary>
		/// Constructs a new instance of the <see cref="BackgroundAutoInputProtectionImage" /> class for derived classes.
		/// </summary>
		/// <remarks>
		/// The dimensions of the specified <paramref name="background"/> image are used as the dimensions of the <see cref="AutoInputProtectionImage.CompositeImage"/>
		/// that will be generated.
		/// </remarks>
		/// <exception cref="ArgumentNullException">The specified <paramref name="background"/> image or <paramref name="textProvider"/> is <see langword="null"/>.</exception>
		/// <exception cref="ArgumentOutOfRangeException">The specified <paramref name="size"/> is less than the value of 
		/// <see cref="AutoInputProtectionImage.MinimumSize"/>.</exception>
		/// <param name="background">The <see cref="Image"/> that will be rendered in the background of the <see cref="AutoInputProtectionImage.CompositeImage"/>.</param>
		/// <param name="textProvider">The <see cref="AutoInputProtectionTextProvider"/> implementation that generates the 
		/// <see cref="AutoInputProtectionImage.Text"/> for the <see cref="AutoInputProtectionImage.CompositeImage"/>.</param>
		protected BackgroundAutoInputProtectionImage(Image background, AutoInputProtectionTextProvider textProvider)
			// NOTE: MinimumSize size is only specified when background is null so that ArgumentNullException may be thrown by this constructor
			// after the base constructor is finished.
			: base((background == null) ? MinimumSize : background.Size, textProvider)
		{
			if (background == null)
				throw new ArgumentNullException("background");

			this.background = background;
		}
		#endregion

		#region Methods
		/// <summary>
		/// Returns an <see cref="Image"/> of the specified <paramref name="size"/> to be used as the surface on which the <see cref="AutoInputProtectionImage.CompositeImage"/> 
		/// will be generated.
		/// </summary>
		/// <remarks>
		/// <para>
		/// The base implementation simply returns the value of the <see cref="Background"/> property, which is the image that was specified when an 
		/// instance of this class was constructed.  If it is <see langword="null"/> then <see cref="AutoInputProtectionImage.CreateCompositeImage()"/> will use a pure white surface
		/// of the specified <paramref name="size"/>.
		/// </para>
		/// <para>
		/// The <paramref name="size"/> argument is ignored.  If the <see cref="Background"/> image is not <see langword="null"/> and it has different
		/// dimensions than the specified <paramref name="size"/> it will be scaled automatically by <see cref="AutoInputProtectionImage.CreateCompositeImage()"/>.
		/// </para>
		/// </remarks>
		/// <param name="size">The dimensions of the image.</param>
		/// <returns>The <see cref="Background"/> image that was specified when an instance of this class was constructed.</returns>
		protected override Image CreateSurfaceImage(Size size)
		{
			return background;
		}

		/// <summary>
		/// When implemented by a derived type, renders the <see cref="AutoInputProtectionImage.Text"/> to the specified <paramref name="graphics"/> object.
		/// </summary>
		/// <remarks>
		/// This method is called by <see cref="AutoInputProtectionImage.CreateCompositeImage()"/> after all of the preprocess <see cref="AutoInputProtectionImage.Filters"/> have 
		/// been applied.
		/// </remarks>
		/// <seealso cref="AutoInputProtectionImage.CompositeImage"/>
		/// <seealso cref="AutoInputProtectionImage.CreateCompositeImage()"/>
		/// <param name="graphics"><see cref="Graphics"/> object that provides the surface on which to draw.</param>
		/// <param name="size">The dimensions of the image.</param>
		protected abstract override void CreateCompositeImage(Graphics graphics, Size size);

		/// <summary>
		/// Releases the unmanaged resources used by an instance of the <see cref="BackgroundAutoInputProtectionImage" /> class and optionally releases the managed resources.
		/// </summary>
		/// <param name="disposing"><see langword="true">True</see> to release both managed and unmanaged resources; <see langword="false"/> to release only unmanaged resources.</param>
		protected override void Dispose(bool disposing)
		{
			try
			{
				if (disposing && background != null)
				{
					background.Dispose();
				}
			}
			finally
			{
				base.Dispose(disposing);
			}
		}
		#endregion
	}
}
